using System;
using System.Collections;
using System.Collections.Generic;
using System.Globalization;
using System.Reflection;
using Microsoft.SharePoint;
using System.Threading;

namespace LetsDoSomeVariations
{
    /// <summary>
    /// Static class that holds the business logic for the LetsDoSomeVariations Feature.
    /// </summary>
    public static class VariationsComponent
    {
        /// <summary>
        /// Creates the variations 
        ///     - set the variationsettings
        ///     - create variationlabels
        ///     - create site hierarchies
        /// </summary>
        /// <param name="web">The web.</param>
        /// <param name="featureProperties">The feature properties.</param>
        public static void CreateVariations(SPWeb web, SPFeaturePropertyCollection featureProperties)
        {
            Console.WriteLine("Process Variation Labels");
            // Get handle to the Variation Settings List
            string varLabelsListId = web.AllProperties["_VarLabelsListId"].ToString();
            SPList variationLabelsList = web.Lists[new Guid(varLabelsListId)];
            if (variationLabelsList.Items.Count > 0)
            {
                throw new SPException("Variation labels already have been created!");
            }

            // Read labels from feature.xml
            VariationLabel[] variationLabels = ReadVariationLabelsFromProperties(featureProperties);
            if (variationLabels != null && variationLabels.Length == 0)
            {
                throw new SPException("Skip creating of variations: No label(s) found!");
            }

            // Add labels to VariationLabels List
            foreach (VariationLabel label in variationLabels)
            {
                Console.WriteLine("Adding label: {0}, {1}, {2}, {3}, IsSource = {4}", label.Label, label.DisplayName, label.Language, label.Locale, label.IsSource);

                SPListItem item = variationLabelsList.Items.Add();

                item[Constants.VariationLabelProperties.HierarchyIsCreated] = false;
                item[Constants.VariationLabelProperties.Title] = label.Label;
                item[Constants.VariationLabelProperties.Description] = label.Description;
                item[Constants.VariationLabelProperties.FlagControlDisplayName] = label.DisplayName;
                item[Constants.VariationLabelProperties.Language] = label.Language;
                item[Constants.VariationLabelProperties.Locale] = label.Locale;
                item[Constants.VariationLabelProperties.HierarchyCreationMode] = "Publishing Sites and All Pages";
                item[Constants.VariationLabelProperties.IsSource] = label.IsSource; ;

                item.Update();
            }

            Console.WriteLine("Process Variation Settings");
            // Get handle to the VariationSettings List
            string varRelationshipsListId = web.AllProperties["_VarRelationshipsListId"].ToString();
            SPList variationSettingsList = web.Lists[new Guid(varRelationshipsListId)];

            // Read settings from feature.xml
            VariationSettings variationSettings = ReadVariationSettingsFromProperties(featureProperties);

            // Update VariationSettings List
            SPListItem variationroot = variationSettingsList.Items[0];
            variationroot["ObjectID"] = string.Format("{0}{1}, {1}", web.Site.Url, variationSettings.ObjectID);
            variationroot.Update();

            Hashtable properties = variationSettingsList.RootFolder.Properties;
            properties[Constants.VariationSettingsProperties.SourceVarRootWebTemplatePropertyName] = variationSettings.SourceVarRootWebTemplatePropertyName;
            properties[Constants.VariationSettingsProperties.EnableAutoSpawnPropertyName] = variationSettings.EnableAutoSpawnPropertyName.ToString();
            properties[Constants.VariationSettingsProperties.AutoSpawnStopAfterDeletePropertyName] = variationSettings.AutoSpawnStopAfterDeletePropertyName.ToString();
            properties[Constants.VariationSettingsProperties.UpdateWebPartsPropertyName] = variationSettings.UpdateWebPartsPropertyName.ToString();
            properties[Constants.VariationSettingsProperties.CopyResourcesPropertyName] = variationSettings.CopyResourcesPropertyName.ToString();
            properties[Constants.VariationSettingsProperties.SendNotificationEmailPropertyName] = variationSettings.SendNotificationEmailPropertyName.ToString();
            variationSettingsList.RootFolder.Update();

            // Create SiteHierarchies
            Console.WriteLine("Create Hierarchies");

            double timeOutMinutes = 5;
            SPFeatureProperty p = featureProperties[Constants.FeatureProperties.CreateHierachyTimeOutMinutes];
            if (p != null)
            {
                double.TryParse(p.Value, out timeOutMinutes);
            }

            CreateSiteHierarchies(variationLabelsList, timeOutMinutes);
        }

        /// <summary>
        /// Reads the variation settings from the feature properties.
        /// 
        /// 	<Property Key ="CreateVariations" Value="True" />
        ///     <Property Key ="CreateHierachyTimeOutMinutes" Value="5" />
        /// 	<Property Key ="VariationHomeUrl" Value="/" />		
        /// 	<Property Key ="SourceVariationTemplateName" Value="BLANKINTERNETCONTAINER#0" />
		/// 	<Property Key ="AutomaticCreationOfSitesAndPages" Value="True" />
		/// 	<Property Key ="RecreateOrDeletedOfTargetPage" Value="True" />
		/// 	<Property Key ="UpdateTargetPageWebParts" Value="True" />
		/// 	<Property Key ="SendEmailNotification" Value="False" />
		/// 	<Property Key ="CopyResources" Value="True" />
		/// 	<Property Key ="Label-1" Value="EN" />
		/// 	<Property Key ="Label-1-DisplayName" Value="English" />
		/// 	<Property Key ="Label-1-Description" Value="" />		
		/// 	<Property Key ="Label-1-Language" Value="en-US" />
		/// 	<Property Key ="Label-1-Locale" Value="1033" />
		/// 	<Property Key ="Label-1-IsSource" Value="False" />
		/// 	<Property Key ="Label-2" Value="NL" />
		/// 	<Property Key ="Label-2-DisplayName" Value="Nederlands" />
		/// 	<Property Key ="Label-2-Description" Value="" />		
		/// 	<Property Key ="Label-2-Language" Value="nl-NL" />
		/// 	<Property Key ="Label-2-Locale" Value="1043" />
        /// 	<Property Key ="Label-2-IsSource" Value="True" />
        /// 
        /// </summary>
        /// <param name="properties">The properties.</param>
        /// <returns>An object with the variationsettings from the feature.xml</returns>
        private static VariationSettings ReadVariationSettingsFromProperties(SPFeaturePropertyCollection properties)
        {
            VariationSettings variationSettings = new VariationSettings();

            SPFeatureProperty p1 = properties[Constants.FeatureProperties.VariationHomeUrl];
            if (p1 != null)
            {
                if (!string.IsNullOrEmpty(p1.Value))
                {
                    string tmp = p1.Value;
                    if (!tmp.StartsWith("/"))
                    {
                        tmp = string.Concat('/', tmp);
                    }
                    variationSettings.ObjectID = tmp;
                }
            }
            SPFeatureProperty p2 = properties[Constants.FeatureProperties.SourceVariationTemplateName];
            if (p2 != null)
            {
                if (!string.IsNullOrEmpty(p2.Value))
                {
                    variationSettings.SourceVarRootWebTemplatePropertyName = p2.Value;
                }
            }
            SPFeatureProperty p3 = properties[Constants.FeatureProperties.AutomaticCreationOfSitesAndPages];
            if (p3 != null)
            {
                bool tmp;
                bool.TryParse(p3.Value, out tmp);
                variationSettings.EnableAutoSpawnPropertyName = tmp;
            }
            SPFeatureProperty p4 = properties[Constants.FeatureProperties.RecreateOrDeletedOfTargetPage];
            if (p4 != null)
            {
                bool tmp;
                bool.TryParse(p4.Value, out tmp);
                variationSettings.AutoSpawnStopAfterDeletePropertyName = !tmp; // Notice!!...Reverse boolean value
            }
            SPFeatureProperty p5 = properties[Constants.FeatureProperties.UpdateTargetPageWebParts];
            if (p5 != null)
            {
                bool tmp;
                bool.TryParse(p5.Value, out tmp);
                variationSettings.UpdateWebPartsPropertyName = tmp;
            }
            SPFeatureProperty p6 = properties[Constants.FeatureProperties.SendEmailNotification];
            if (p6 != null)
            {
                bool tmp;
                bool.TryParse(p6.Value, out tmp);
                variationSettings.SendNotificationEmailPropertyName = tmp;
            }
            SPFeatureProperty p7 = properties[Constants.FeatureProperties.CopyResources];
            if (p7 != null)
            {
                bool tmp;
                bool.TryParse(p7.Value, out tmp);
                variationSettings.CopyResourcesPropertyName = tmp;
            }

            return variationSettings;
        }

        /// <summary>
        /// Reads the variation labels from the feature properties.
        /// </summary>
        /// <param name="properties">The properties.</param>
        /// <returns>An array of VariationLabels from the feature.xml</returns>
        private static VariationLabel[] ReadVariationLabelsFromProperties(SPFeaturePropertyCollection properties)
        {
            List<VariationLabel> list = new List<VariationLabel>();

            SPFeatureProperty p = properties[string.Format(Constants.FeatureProperties.Label, "1")];
            if (p != null)
            {
                int count = 1;
                bool continueLoop = true;
                while (continueLoop)
                {
                    continueLoop = false;

                    string key1 = string.Format(Constants.FeatureProperties.Label, count);
                    string key2 = string.Format(Constants.FeatureProperties.LabelDisplayName, count);
                    string key3 = string.Format(Constants.FeatureProperties.LabelDescription, count);
                    string key4 = string.Format(Constants.FeatureProperties.LabelLanguage, count);
                    string key5 = string.Format(Constants.FeatureProperties.LabelLocale, count);
                    string key6 = string.Format(Constants.FeatureProperties.LabelIsSource, count);

                    VariationLabel label = new VariationLabel();

                    SPFeatureProperty p1 = properties[key1];
                    if (p1 != null)
                    {
                        label.Label = p1.Value;

                        SPFeatureProperty p2 = properties[key2];
                        if (p2 != null)
                        {
                            label.DisplayName = p2.Value;
                        }
                        SPFeatureProperty p3 = properties[key3];
                        if (p3 != null)
                        {
                            label.Description = p3.Value;
                        }
                        SPFeatureProperty p4 = properties[key4];
                        if (p4 != null)
                        {
                            label.Language = p4.Value;
                        }
                        SPFeatureProperty p5 = properties[key5];
                        if (p5 != null)
                        {
                            int tmp;
                            int.TryParse(p5.Value, out tmp);
                            label.Locale = tmp;
                        }
                        SPFeatureProperty p6 = properties[key6];
                        if (p6 != null)
                        {
                            bool tmp1;
                            bool.TryParse(p6.Value, out tmp1);
                            label.IsSource = tmp1;
                        }

                        if (!string.IsNullOrEmpty(label.Label) && !string.IsNullOrEmpty(label.DisplayName) && !string.IsNullOrEmpty(label.Language) && label.Locale > 0)
                        {
                            list.Add(label);
                            count++;
                            continueLoop = true;
                        }
                    }
                }
            }

            return list.ToArray();
        }

        /// <summary>
        /// Creates the site hierarchies.
        /// </summary>
        /// <param name="variationLabelsList">The variationlabels list.</param>
        /// <param name="timeOutMinutes">The minutes to wait before timeout, while the hierachies are beeing created.</param>
        private static void CreateSiteHierarchies(SPList variationLabelsList, double timeOutMinutes)
        {
            // I know it's dirty!...but lets use some reflection.
            // 
            // This is the only stable way I found to push the 'Create Hierarchies' button on different language installations of MOSS2007
            // I hope that MS will make this a public class soon, instead of keeping it internal.
            
            Assembly asm = Assembly.GetAssembly(typeof(Microsoft.SharePoint.Publishing.PublishingSite));
            if (asm != null)
            {
                Type type = asm.GetType("Microsoft.SharePoint.Publishing.Internal.WebControls.CreateVariationHierarchiesLro", false, false);
                if (type != null)
                {
                    Console.WriteLine("Waiting for hierarchy to be created. This can take several minutes!");
                    
                    SPWeb web = variationLabelsList.ParentWeb;

                    object lro = Activator.CreateInstance(type, BindingFlags.Instance | BindingFlags.NonPublic, null, new object[] { web.Site.Url }, CultureInfo.CurrentCulture);
                    PropertyInfo pi = type.GetProperty("RedirectWhenFinished");
                    pi.SetValue(lro, false, null);

                    type.InvokeMember("Start", BindingFlags.InvokeMethod, null, lro, new object[] { web });

                    // Wait for hierachies beeing created.
                    bool isNormalFinish = false;
                    DateTime endTime = DateTime.Now.AddMinutes(timeOutMinutes);
                    while (DateTime.Now < endTime)
                    {
                        int hierarchyIsCreatedCounter = 0;

                        SPListItemCollection items = variationLabelsList.Items;
                        foreach (SPListItem item in items)
                        {
                            bool hierarchyIsCreated = false;
                            object tmp = item[Constants.VariationLabelProperties.HierarchyIsCreated];
                            bool.TryParse(tmp.ToString(), out hierarchyIsCreated);

                            if (hierarchyIsCreated)
                            {
                                hierarchyIsCreatedCounter++;
                            }
                        }

                        if (hierarchyIsCreatedCounter == items.Count)
                        {
                            isNormalFinish = true;
                            break;
                        }

                        Thread.Sleep(1000); // sleep for little while.
                    }

                    if (!isNormalFinish)
                    {
                        throw new SPException(string.Format("Time out ({0} minutes)! While Creating Hierarchies!...It is possible that the hierarchies are not created completly.", timeOutMinutes));
                    }
                }
            }
        }
    }
}
